package org.abc.fund.service.dataSourceCollection;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.abc.fund.dto.dataSource.JoinQuantResultDTO;
import org.abc.fund.entity.funds.FundBasicInfo;
import org.abc.fund.entity.funds.FundCompany;
import org.abc.fund.entity.funds.FundManager;
import org.abc.fund.repository.funds.FundBasicInfoRepository;
import org.abc.fund.repository.funds.FundCompanyRepository;
import org.abc.fund.repository.funds.FundManagerRepository;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class FundUniverseService {

    private final JoinQuantDataIngestionService ingestionService;
    private final FundBasicInfoRepository fundBasicInfoRepository;
    private final FundCompanyRepository fundCompanyRepository;
    private final FundManagerRepository fundManagerRepository;
    @Transactional
    public Map<String, Object> initializeFundUniverse(
            String username, String password, int limit, List<String> fundTypes) {

        List<Map<String, Object>> aggregatedRaw = new ArrayList<>();
        if (fundTypes == null || fundTypes.isEmpty()) {
            aggregatedRaw.addAll(fetchFundListFromJoinQuant(username, password, limit, null));
        } else {
            for (String type : fundTypes) {
                if (type == null || type.isBlank()) {
                    continue;
                }
                aggregatedRaw.addAll(fetchFundListFromJoinQuant(
                        username,
                        password,
                        limit,
                        List.of(type.trim())
                ));
            }
        }

        if (aggregatedRaw.isEmpty()) {
            return Map.of(
                    "status", "success",
                    "message", "未获取到基金数据",
                    "total", 0,
                    "progress", 100,
                    "preview", List.of()
            );
        }
        List<FundBasicInfo> fundsToSave = aggregatedRaw.stream()
                .map(this::mapToFundBasicInfo)
                .filter(info -> info != null && info.getCode() != null)
                .collect(Collectors.toMap(
                        FundBasicInfo::getCode,
                        info -> info,
                        (existing, replacement) -> existing,
                        LinkedHashMap::new
                ))
                .values()
                .stream()
                .collect(Collectors.toList());
        List<FundBasicInfo> savedFunds = fundBasicInfoRepository.saveAll(fundsToSave);
        int total = savedFunds.size();
        List<FundBasicInfo> preview = savedFunds.stream().limit(10).toList();
        return Map.of(
                "status", "success",
                "message", "初始化基金主体信息成功",
                "total", total,
                "progress", 100,
                "preview", preview
        );
    }

    private List<Map<String, Object>> fetchFundListFromJoinQuant(String username,
                                                                 String password,
                                                                 int limit,
                                                                 List<String> singleFundTypeList) {
        Map<String, Object> params = new HashMap<>();
        params.put("data_type", "ALL_FUND_LIST");
        params.put("limit", limit);
        if (singleFundTypeList != null && !singleFundTypeList.isEmpty()) {
            params.put("fund_types", singleFundTypeList);
        }
        try {
            JoinQuantResultDTO scriptResult = ingestionService.ingestData(username, password, params);
            if (!"success".equalsIgnoreCase(scriptResult.getStatus())) {
                String message = scriptResult.getMessage();
                throw buildFriendlyException(message);
            }
            List<Map<String, Object>> rawData = scriptResult.getRawData();
            if (rawData == null) {
                return List.of();
            }
            return rawData;
        } catch (ResponseStatusException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new ResponseStatusException(
                    HttpStatus.INTERNAL_SERVER_ERROR,
                    "调用聚宽接口时发生异常：" + ex.getMessage(),
                    ex
            );
        }
    }

    private ResponseStatusException buildFriendlyException(String message) {
        String friendly = message != null ? message : "聚宽接口返回未知错误";
        if (friendly.contains("认证失败") || friendly.contains("auth")) {
            return new ResponseStatusException(
                    HttpStatus.UNAUTHORIZED,
                    "聚宽账号认证失败，请确认用户名和密码正确"
            );
        }
        if (friendly.toLowerCase().contains("timeout")) {
            return new ResponseStatusException(
                    HttpStatus.GATEWAY_TIMEOUT,
                    "聚宽接口超时，请稍后重试"
            );
        }
        return new ResponseStatusException(
                HttpStatus.BAD_GATEWAY,
                "调用聚宽接口失败：" + friendly
        );
    }
    private String generateShortCompanyName(String fullName) {
        if (fullName == null) return null;

        return fullName
                .replace("基金管理有限公司", "")
                .replace("资产管理有限公司", "")
                .replace("有限责任公司", "")
                .replace("有限公司", "")
                .trim();
    }
    private String generateCompanyRating(String companyName) {
        if (companyName == null || companyName.isBlank()) {
            return "D"; // 默认最低
        }
        int hash = Math.abs(companyName.hashCode());
        int bucket = hash % 3;  // 分成 3 个等级（AAA / AA / A）

        switch (bucket) {
            case 0: return "A";
            case 1: return "B";
            default: return "C";
        }
    }
    private FundBasicInfo mapToFundBasicInfo(Map<String, Object> data) {
        String mainCode = (String) data.get("main_code");
        if (mainCode == null || mainCode.isBlank()) {
            return null;
        }
        String fundCode = (String) data.get("code");
        if (fundCode == null || fundCode.isBlank()) {
            fundCode = mainCode;
        }
        FundBasicInfo fund = fundBasicInfoRepository.findById(fundCode).orElse(new FundBasicInfo());
        fund.setCode(fundCode);
        fund.setMainCode(mainCode);
        fund.setFundType((String) data.get("fund_type"));
        //完整的基金代码
        fund.setName((String) data.get("name"));
        /* ---------- 处理基金公司（trustee） ---------- */
        FundCompany company = null;
        String companyName = (String) data.get("trustee");
        if (companyName != null && !companyName.isBlank()) {
            company = fundCompanyRepository.findByName(companyName).orElse(null);
            if (company == null) {
                company = new FundCompany();
                company.setName(companyName);
                company.setShortName(generateShortCompanyName(companyName)); // 生成简称
                company.setRating(generateCompanyRating(companyName));       // 生成评级，不会重复叠加
                company = fundCompanyRepository.save(company);
            }
            fund.setCompany(company);
        }
        /* ---------- 处理基金经理（advisor） ---------- */
        String managerName = (String) data.get("advisor");
        if (managerName != null && !managerName.isBlank()) {
            int existingFundCount = fundBasicInfoRepository.countByManager_Name(managerName);
            FundManager manager = fundManagerRepository.findByName(managerName).orElse(null);
            if (manager == null) {
                manager = new FundManager();
                manager.setName(managerName);
                manager.setIntro("基金经理 " + managerName + " 的详细资料暂未录入。");
                manager.setFundCount(existingFundCount + 1);
                if (company != null) {
                    manager.setCompany(company);
                }
                manager = fundManagerRepository.save(manager);
            } else {
                manager.setFundCount(existingFundCount + 1);
                if (manager.getCompany() == null && company != null) {
                    manager.setCompany(company);
                }
                manager = fundManagerRepository.save(manager);
            }
            fund.setManager(manager);
        }

        fund.setOperateModeId(parseInteger(data.get("operate_mode_id")));
        fund.setOperateMode((String) data.get("operate_mode"));
        fund.setUnderlyingAssetTypeId(parseInteger(data.get("underlying_asset_type_id")));
        fund.setUnderlyingAssetType((String) data.get("underlying_asset_type"));
        fund.setInvestStyleId(parseInteger(data.get("invest_style_id")));
        fund.setInvestStyle((String) data.get("invest_style"));
        fund.setStatus("在市");
        fund.setStatisticsMainCode((String) data.get("statistics_main_code"));
        Object pubDateObj = data.get("pub_date");
        if (pubDateObj instanceof String) {
            try {
                fund.setPubDate(LocalDate.parse((String) pubDateObj));
            } catch (Exception e) {
                log.warn("基金 {} 的发行日期解析失败：{}", mainCode, pubDateObj);
            }
        }
        Object startDateObj = data.get("start_date");
        if (startDateObj instanceof String) {
            try {
                fund.setStartDate(LocalDate.parse((String) startDateObj));
            } catch (Exception e) {
                log.warn("基金 {} 的成立日期解析失败：{}", mainCode, startDateObj);
            }
        }
        Object endDateObj = data.get("end_date");
        if (endDateObj instanceof String) {
            try {
                fund.setEndDate(LocalDate.parse((String) endDateObj));
            } catch (Exception e) {
                log.warn("基金 {} 的终止日期解析失败：{}", mainCode, endDateObj);
            }
        }
        //兼容旧type字段
        fund.setType(fund.getUnderlyingAssetType());
        return fund;
    }
    private Integer parseInteger(Object obj) {
        if (obj == null) return null;

        if (obj instanceof Integer) {
            return (Integer) obj;
        }

        if (obj instanceof Number) {
            return ((Number) obj).intValue();
        }

        if (obj instanceof String) {
            try {
                return Integer.parseInt((String) obj);
            } catch (Exception e) {
                return null;
            }
        }

        return null;
    }

}

